#include "clock.h"
#include <time.h>

Clock_def_t CurrentTime;

/**
 * RTC task, only used for initialization
 */
void vTaskCTRL_TIME(void)
{
    init_HORLOGE();

    vTaskDelete(NULL);
}

void init_HORLOGE(void)
{
    /* Chek if rtc is configured */
    if (BKP_ReadBackupRegister(BKP_DR1 ) != 0xA5A5)
    {
        /* RTC Configuration */
        RTC_Configuration();
    }
    else
    {
        /* Wait for RTC registers synchronization */
        RTC_WaitForSynchro();

        /* Enable the RTC Second */
        RTC_ITConfig(RTC_IT_SEC, ENABLE);

        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();
    }

    /* Clear reset flags */
    RCC_ClearFlag();
}

/**
 * @brief  Configures the RTC.
 * @param  None
 * @retval None
 */
void RTC_Configuration(void)
{
    /* Enable PWR and BKP clocks */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    /* Allow access to BKP Domain */
    PWR_BackupAccessCmd(ENABLE);

    /* Reset Backup Domain */
    BKP_DeInit();

    /* Enable LSE */
    RCC_LSEConfig(RCC_LSE_ON );
    /* Wait till LSE is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_LSERDY ) == RESET)
    {
    }

    /* Select LSE as RTC Clock Source */
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE );

    /* Enable RTC Clock */
    RCC_RTCCLKCmd(ENABLE);

    /* Wait for RTC registers synchronization */
    RTC_WaitForSynchro();

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();

    /* Enable the RTC Second */
    RTC_ITConfig(RTC_IT_SEC, ENABLE);

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();

    /* Set RTC prescaler: set RTC period to 1sec */
    RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();
}

void RTC_SetHours(uint8_t hours)
{
    CurrentTime.hours = hours;
}

/**
 * @brief  Adjusts time.
 * @param  None
 * @retval None
 */
void Time_Adjust()
{
    struct tm t;

    t.tm_hour = CurrentTime.hours;
    t.tm_min = CurrentTime.minutes;
    t.tm_sec = CurrentTime.minutes;
    t.tm_mday = CurrentTime.day;
    t.tm_mon = CurrentTime.month;
    t.tm_year = CurrentTime.year;
    t.tm_isdst = CurrentTime.dst;

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();

    /* Change the current time */
    RTC_SetCounter(encodeDateTime(&t));

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();

    BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
}

/**
 * @brief  Displays the current time.
 * @param  TimeVar: RTC counter value.
 */
void Time_Display(uint32_t TimeVar)
{
    uint32_t THH = 0, TMM = 0, TSS = 0;

    /* Compute  hours */
    THH = TimeVar / 3600;
    /* Compute minutes */
    TMM = (TimeVar % 3600) / 60;
    /* Compute seconds */
    TSS = (TimeVar % 3600) % 60;

    printf("Time: %ld:%ld:%ld\r", THH, TMM, TSS);
}

time_t encodeDateTime(struct tm *t)
{
    time_t t_of_day;

    t_of_day = mktime(t);

    return (t_of_day);
}

void decodeDateTime(time_t datetime, struct tm *t)
{
    //t = localtime(&datetime);
}

/**
 * @brief Format time in string
 */
void getTime(char *str)
{
    time_t total_time;
    struct tm t;
    char tab[80];

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);
    strftime(tab, sizeof(tab), "%d-%m-%Y %H:%M:%S", &t);
    strcpy(str, tab);
}

/**
 * @brief Get time in second
 */
uint32_t CLOCK_getHoursInSecond(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();
    t = *localtime(&total_time);

    return ((t.tm_hour * 3600) + (t.tm_min * 60) + t.tm_sec);
}

/**
 * @brief Get hours
 */
uint8_t getHour(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);

    return (t.tm_hour);
}

/**
 * @brief Get minutes
 */
uint8_t getMin(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);

    return (t.tm_min);
}

/**
 * @brief Get secondes
 */
uint8_t getSec(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);
    return (t.tm_sec);
}

/**
 * @brief Day light saving (DST)
 */
uint8_t getDayLightSaving(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);
    return (t.tm_isdst);
}

/**
 * @brief Nb day since January 1
 */
uint16_t getDaySinceYearStart(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);
    return (t.tm_yday);
}

/**
 * @brief Get month
 */
uint16_t getMonth(void)
{
    time_t total_time;
    struct tm t;

    total_time = (time_t) RTC_GetCounter();

    t = *localtime(&total_time);
    return (t.tm_mon);
}
